/**
 * Title: RoleServiceImpl.java
 * Description: Copyright: Copyright (c) 2019 Company: BHFAE
 *
 * @author Sharp
 * @date 2019-9-15 14:10
 * @description Project Name: Grote
 * @Package: com.srct.service.account.service.impl
 */
package com.sharp.authorization.service.permit.impl;

import com.sharp.authorization.dao.common.entity.AcRole;
import com.sharp.authorization.dao.common.entity.AcUser;
import com.sharp.authorization.dao.common.entity.AcUserRole;
import com.sharp.authorization.dao.common.repository.AcRolePermitService;
import com.sharp.authorization.dao.common.repository.AcRoleService;
import com.sharp.authorization.dao.common.repository.AcUserRoleService;
import com.sharp.authorization.dao.common.repository.AcUserService;
import com.sharp.authorization.dao.join.repository.UserJoinRoleService;
import com.sharp.authorization.service.permit.AuthRoleService;
import com.sharp.authorization.vo.role.*;
import com.sharp.kernel.constant.CommonConst;
import com.sharp.kernel.constant.db.SqlConstant;
import com.sharp.kernel.constant.err.ErrCodeSys;
import com.sharp.kernel.utils.ReflectionUtil;
import com.sharp.kernel.validate.Validator;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service
public class AuthRoleServiceImpl implements AuthRoleService {

    @Resource
    private AcUserService acUserService;
    @Resource
    private AcUserRoleService acUserRoleService;
    @Resource
    private AcRoleService acRoleService;
    @Resource
    private UserJoinRoleService userJoinRoleService;
    @Resource
    private AcRolePermitService acRolePermitService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void bindUserRole(String loginId, String roleId) {
        AcUser user = acUserService.getUserByLoginId(loginId);
        Validator.assertNotNull(user, ErrCodeSys.PA_PARAM_NULL, "用户名");
        Validator.assertTrue(acRoleService.existedWithPrimaryKey(roleId), ErrCodeSys.PA_DATA_NOT_EXIST, "角色ID");
        AcUserRole userRole = buildUserRole(user.getId(), roleId);
        acUserRoleService.insertOrUpdate(userRole);
    }

    private AcUserRole buildUserRole(String userId, String roleId) {
        AcUserRole userRole = new AcUserRole();
        userRole.setUserId(userId);
        userRole.setRoleId(roleId);
        return userRole;
    }

    @Override
    public void unbindUserRole(String loginId, String roleId) {
        AcUser user = acUserService.getUserByLoginId(loginId);
        Validator.assertNotNull(user, ErrCodeSys.PA_PARAM_NULL, "用户名");
        AcUserRole userRole = acUserRoleService.getUserRoleByRoleIdAndUserId(roleId, user.getId());
        Validator.assertNotNull(userRole, ErrCodeSys.PA_PARAM_NULL, "该用户没有该角色");
        acUserRoleService.deleteByPrimaryKey(userRole);
    }

    @Override
    public List<RoleRes> getRoleListByUserId(String userId) {
        List<RoleRes> resList = new ArrayList<>();
        List<AcRole> allRoleList = acRoleService.select();
        List<AcRole> roleList = userJoinRoleService.getUserWithRoleListByUserId(userId).getRoleList();
        for (AcRole role : allRoleList) {
            RoleRes res = ReflectionUtil.copy(role, RoleRes.class);
            if (roleList.contains(role)) {
                res.setBind(CommonConst.YES);
            }
            resList.add(res);
        }
        return resList;
    }

    @Override
    public List<AcRole> getSubRoleList(String parentRoleId) {
        return acRoleService.getRoleByParentRoleId(parentRoleId);
    }

    @Override
    public List<RoleTreeRes> queryRoleTree() {
        List<AcRole> roleList = acRoleService.selectValid();
        return buildRoleTree(roleList);
    }

    @Override
    public List<RoleRes> queryRole(QueryRoleReq req) {
        List<RoleRes> resList = new ArrayList<>();
        List<AcRole> roleList = acRoleService.selectValid();
        Map<String, AcRole> roleIdMap = new HashMap<>(roleList.size());
        for (AcRole role : roleList) {
            roleIdMap.put(role.getId(), role);
        }
        List<AcRole> queryResult = acRoleService.getRoleByParentRoleName(req.getRoleName(), req.getParentRoleName());
        for (AcRole role : queryResult) {
            RoleRes res = ReflectionUtil.copy(role, RoleRes.class);
            if (role.getParentRoleId() != null) {
                res.setParentRoleName(roleIdMap.get(role.getParentRoleId()).getName());
            }
            resList.add(res);
        }
        return resList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addRole(AddRoleReq req) {
        AcRole role = ReflectionUtil.copy(req, AcRole.class);
        role.setValid(SqlConstant.VALID);
        acRoleService.insertSelective(role);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateRole(UpdateRoleReq req) {
        AcRole role = ReflectionUtil.copy(req, AcRole.class);
        role.setValid(SqlConstant.VALID);
        acRoleService.updateByPrimaryKeySelective(role);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRole(DeleteRoleReq req) {
        List<AcUserRole> userRoleList = acUserRoleService.getUserRoleByRoleId(req.getId());
        Validator.assertTrue(CollectionUtils.isEmpty(userRoleList), ErrCodeSys.SYS_ERR_MSG, "该角色下有用户,不可删除");
        List<AcRole> roleList = acRoleService.getRoleByParentRoleId(req.getId());
        Validator.assertTrue(CollectionUtils.isEmpty(roleList), ErrCodeSys.SYS_ERR_MSG, "有下属角色,不可删除");
        AcRole role = ReflectionUtil.copy(req, AcRole.class);
        acRolePermitService.deleteByRoleId(role.getId());
        acRoleService.deleteByPrimaryKey(role);
    }

    private List<RoleTreeRes> buildRoleTree(List<AcRole> roleList) {
        List<RoleTreeRes> res = new ArrayList<>();
        List<AcRole> parentRoleList =
                roleList.stream().filter(role -> role.getParentRoleId() == null).collect(Collectors.toList());
        parentRoleList.forEach(parentRole -> res.add(buildRoleTree(parentRole, roleList)));
        return res;
    }

    private RoleTreeRes buildRoleTree(AcRole parentRole, List<AcRole> roleList) {
        RoleTreeRes roleTreeRes = ReflectionUtil.copy(parentRole, RoleTreeRes.class);
        List<AcRole> list =
                roleList.stream().filter(role -> parentRole.getId().equals(role.getParentRoleId()))
                        .collect(Collectors.toList());
        list.forEach(subRole -> roleTreeRes.getSubRole().add(buildRoleTree(subRole, roleList)));
        return roleTreeRes;
    }
}
